Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\runtime\src\message\payload\list.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::message::payload::list_base::impl_list_base;
30
use crate::message::{Error, FromBytes, FromBytesWithOffsets, Message, WriteTo};
31
use crate::util::ToUsize;
32
use std::io::Write;
33
use std::marker::PhantomData;
34
35
#[derive(Copy, Clone, Debug)]
36
pub struct List<B, T, Item> {
37
    data: B,
38
    len: usize,
39
    useless: PhantomData<T>,
40
    useless1: PhantomData<Item>,
41
}
42
43
impl<B, T, Item> List<B, T, Item> {
44
    /// Creates a list from raw parts.
45
    /// This function assumes that data has the number of items specified by len.
46
    /// A wrong length will simply cause an error (truncated) to be returned if the actual buffer
47
    /// has not enough bytes to contain all items.
48
    ///
49
    /// # Arguments
50
    ///
51
    /// * `data`: the data buffer.
52
    /// * `len`: the number of items to be read from the buffer.
53
    ///
54
    /// # Safety
55
    ///
56
    ///
57
    /// For all array types, (i.e. lists with fixed size items), a wrong length could result
58
    /// in UB where the array iterator, getter or setter attempts to slice out of bounds
59
    /// with a future optimization in release builds, currently it will result in a panic.
60
45
    pub fn from_raw_parts(data: B, len: usize) -> List<B, T, Item> {
61
45
        List {
62
45
            data,
63
45
            len,
64
45
            useless: PhantomData,
65
45
            useless1: PhantomData,
66
45
        }
67
45
    }
68
69
15
    pub fn new(data: B) -> List<B, T, Item> {
70
15
        List::from_raw_parts(data, 0)
71
15
    }
72
}
73
74
impl<B: AsRef<[u8]>, T, Item> List<B, T, Item> {
75
15
    pub fn to_ref<Item1>(&self) -> List<&[u8], T, Item1> {
76
15
        List::from_raw_parts(self.data.as_ref(), self.len)
77
15
    }
78
}
79
80
impl_list_base!(List);
81
82
impl<B: Write, T, I> List<B, T, I> {
83
33
    pub fn write_item<'a, Item: WriteTo<Input<'a> = Item>>(&mut self, item: &Item) -> Result<(), Error> {
84
33
        Item::write_to(item, &mut self.data)
?0
;
85
33
        self.len += 1;
86
33
        Ok(())
87
33
    }
88
89
0
    pub fn write_items<'a, Item: WriteTo<Input<'a> = Item>>(&mut self, items: &[Item]) -> Result<(), Error> {
90
0
        for item in items {
91
0
            self.write_item(item)?;
92
        }
93
0
        Ok(())
94
0
    }
95
}
96
97
impl<'a, T: FromBytes<'a, Output: ToUsize>, Item: FromBytes<'a, Output = Item>> FromBytes<'a>
98
    for List<&'a [u8], T, Item>
99
{
100
    type Output = List<&'a [u8], T, Item>;
101
102
8
    fn from_bytes(slice: &'a [u8]) -> Result<Message<Self::Output>, Error> {
103
8
        let msg = T::from_bytes(slice)
?0
;
104
8
        let control_size = msg.size();
105
8
        let len = msg.into_inner().to_usize();
106
8
        let data = &slice[control_size..];
107
8
        let mut total_size: usize = 0;
108
8
        for _ in 0..len {
109
16
            let msg = Item::from_bytes(&data[total_size..])
?0
;
110
16
            total_size += msg.size();
111
        }
112
8
        let data = &slice[control_size..control_size + total_size];
113
8
        Ok(Message::new(total_size + control_size, List::from_raw_parts(data, len)))
114
8
    }
115
}
116
117
impl<B: AsRef<[u8]>, T, Item> List<B, T, Item> {
118
    /// Returns an iterator over the elements contained in this list.
119
15
    pub fn iter(&self) -> Iter<Item> {
120
15
        Iter {
121
15
            data: self.data.as_ref(),
122
15
            len: self.len,
123
15
            useless: PhantomData,
124
15
        }
125
15
    }
126
127
    /// Returns an iterator over the elements, with their offsets, contained in this list.
128
0
    pub fn iter_offsets(&self) -> IterOffsets<Item> {
129
0
        IterOffsets {
130
0
            data: self.data.as_ref(),
131
0
            len: self.len,
132
0
            useless: PhantomData,
133
0
        }
134
0
    }
135
}
136
137
impl<'a, T, Item> List<&'a [u8], T, Item> {
138
    /// This function is a duplicate of iter specially for cases where lifetime propagation is
139
    /// required.
140
0
    pub fn iter_ref(&self) -> Iter<'a, Item> {
141
0
        Iter {
142
0
            data: self.data.as_ref(),
143
0
            len: self.len,
144
0
            useless: PhantomData,
145
0
        }
146
0
    }
147
148
    /// This function is a duplicate of iter_offsets specially for cases where lifetime propagation is
149
    /// required.
150
0
    pub fn iter_offsets_ref(&self) -> IterOffsets<'a, Item> {
151
0
        IterOffsets {
152
0
            data: self.data.as_ref(),
153
0
            len: self.len,
154
0
            useless: PhantomData,
155
0
        }
156
0
    }
157
}
158
159
pub struct Unsized<T, Item> {
160
    useless: PhantomData<T>,
161
    useless1: PhantomData<Item>,
162
}
163
164
impl<'a, T: FromBytes<'a, Output: ToUsize>, Item> FromBytes<'a> for Unsized<T, Item> {
165
    type Output = List<&'a [u8], T, Item>;
166
167
3
    fn from_bytes(slice: &'a [u8]) -> crate::message::Result<Message<Self::Output>> {
168
3
        let msg = T::from_bytes(slice)
?0
;
169
3
        let control_size = msg.size();
170
3
        let len = msg.into_inner().to_usize();
171
3
        let data = &slice[control_size..];
172
3
        Ok(Message::new(slice.len(), List::from_raw_parts(data, len)))
173
3
    }
174
}
175
176
pub struct Sized<B, T, S, Item> {
177
    useless: PhantomData<T>,
178
    useless1: PhantomData<S>,
179
    useless2: PhantomData<Item>,
180
    useless3: PhantomData<B>,
181
}
182
183
impl<'a, B, T: FromBytes<'a, Output: ToUsize>, S: FromBytes<'a, Output: ToUsize>, Item> FromBytes<'a>
184
    for Sized<B, T, S, Item>
185
{
186
    type Output = List<&'a [u8], T, Item>;
187
188
4
    fn from_bytes(slice: &'a [u8]) -> crate::message::Result<Message<Self::Output>> {
189
4
        let msg = T::from_bytes(slice)
?0
;
190
4
        let mut control_size = msg.size();
191
4
        let len = msg.into_inner().to_usize();
192
4
        let msg = S::from_bytes(&slice[control_size..])
?0
;
193
4
        control_size += msg.size();
194
4
        let total_size = control_size + msg.into_inner().to_usize();
195
4
        let data = &slice[control_size..total_size];
196
4
        Ok(Message::new(total_size, List::from_raw_parts(data, len)))
197
4
    }
198
}
199
200
impl<B: AsRef<[u8]>, T: WriteTo<Input<'static>: ToUsize>, S: WriteTo<Input<'static>: ToUsize>, Item> WriteTo
201
    for Sized<B, T, S, Item>
202
{
203
    type Input<'b> = List<B, T, Item>;
204
205
4
    fn write_to<W: Write>(input: &Self::Input<'_>, mut out: W) -> crate::message::Result<()> {
206
4
        T::write_to(&T::Input::from_usize(input.len), &mut out)
?0
;
207
4
        S::write_to(&S::Input::from_usize(input.data.as_ref().len()), &mut out)
?0
;
208
4
        out.write_all(input.data.as_ref())
?0
;
209
4
        Ok(())
210
4
    }
211
}
212
213
#[cfg(feature = "tokio")]
214
impl<
215
        B: AsRef<[u8]>,
216
        T: crate::message::WriteToAsync<Input<'static>: ToUsize>,
217
        S: crate::message::WriteToAsync<Input<'static>: ToUsize>,
218
        Item,
219
    > crate::message::WriteToAsync for Sized<B, T, S, Item>
220
{
221
0
    async fn write_to_async<W: tokio::io::AsyncWriteExt + Unpin>(
222
0
        input: &Self::Input<'_>,
223
0
        mut out: W,
224
0
    ) -> crate::message::Result<()> {
225
0
        T::write_to_async(&T::Input::from_usize(input.len), &mut out).await?;
226
0
        S::write_to_async(&S::Input::from_usize(input.data.as_ref().len()), &mut out).await?;
227
0
        out.write_all(input.data.as_ref()).await?;
228
0
        Ok(())
229
0
    }
230
}
231
232
pub struct Iter<'a, Item> {
233
    data: &'a [u8],
234
    len: usize,
235
    useless: PhantomData<Item>,
236
}
237
238
impl<'a, Item: FromBytes<'a, Output = Item>> Iterator for Iter<'a, Item> {
239
    type Item = crate::message::Result<Item>;
240
241
33
    fn next(&mut self) -> Option<Self::Item> {
242
33
        if self.len == 0 {
  Branch (242:12): [Folded - Ignored]
  Branch (242:12): [Folded - Ignored]
  Branch (242:12): [True: 0, False: 3]
  Branch (242:12): [True: 0, False: 8]
  Branch (242:12): [True: 0, False: 3]
  Branch (242:12): [True: 0, False: 8]
  Branch (242:12): [True: 0, False: 3]
  Branch (242:12): [True: 0, False: 8]
243
0
            return None;
244
33
        }
245
33
        let msg = match Item::from_bytes(self.data) {
246
0
            Err(e) => return Some(Err(e)),
247
33
            Ok(v) => v,
248
        };
249
33
        self.data = &self.data[msg.size()..];
250
33
        self.len -= 1;
251
33
        Some(Ok(msg.into_inner()))
252
33
    }
253
}
254
255
pub struct IterOffsets<'a, Item> {
256
    data: &'a [u8],
257
    len: usize,
258
    useless: PhantomData<Item>,
259
}
260
261
impl<'a, Item: FromBytes<'a, Output = Item> + FromBytesWithOffsets<'a>> Iterator for IterOffsets<'a, Item> {
262
    type Item = crate::message::Result<(Item, Item::Offsets)>;
263
264
0
    fn next(&mut self) -> Option<Self::Item> {
265
0
        if self.len == 0 {
  Branch (265:12): [Folded - Ignored]
  Branch (265:12): [Folded - Ignored]
266
0
            return None;
267
0
        }
268
0
        let msg = match Item::from_bytes_with_offsets(self.data) {
269
0
            Err(e) => return Some(Err(e)),
270
0
            Ok(v) => v,
271
        };
272
0
        self.data = &self.data[msg.size()..];
273
0
        self.len -= 1;
274
0
        Some(Ok(msg.into_inner()))
275
0
    }
276
}